package com.ruoyi.system.controller;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.ruoyi.system.domain.Event;
import com.ruoyi.system.domain.Preferential;
import com.ruoyi.system.service.IEventService;
import com.ruoyi.system.util.IdWorker;
import com.ruoyi.system.util.ResultObject;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.system.domain.Seckill;
import com.ruoyi.system.service.ISeckillService;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.page.TableDataInfo;

/**
 * 秒杀Controller
 * 
 * @author ruoyi
 * @date 2022-12-26
 */
@RestController
@RequestMapping("/event/seckill")
public class SeckillController extends BaseController
{
    @Autowired
    private ISeckillService seckillService;

    @Autowired
    IdWorker idWorker;

    private Lock lock=new ReentrantLock(true);


    @Autowired
    RedisTemplate redisTemplate;


    @Autowired
    IEventService iEventService;


    @Autowired
    RabbitTemplate rabbitTemplate;
    /**
     * 查询秒杀列表
     */
    @RequiresPermissions("system:seckill:list")
    @GetMapping("/list")
    public TableDataInfo list(Seckill seckill)
    {
        startPage();
        List<Seckill> list = seckillService.selectSeckillList(seckill);
        return getDataTable(list);
    }

    /**
     * 导出秒杀列表
     */
    @RequiresPermissions("system:seckill:export")
    @Log(title = "秒杀", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, Seckill seckill)
    {
        List<Seckill> list = seckillService.selectSeckillList(seckill);
        ExcelUtil<Seckill> util = new ExcelUtil<Seckill>(Seckill.class);
        util.exportExcel(response, list, "秒杀数据");
    }

    /**
     * 获取秒杀详细信息
     */
    @RequiresPermissions("system:seckill:query")
    @GetMapping(value = "query/{sid}")
    public AjaxResult getInfo(@PathVariable("sid") Long sid)
    {
        return AjaxResult.success(seckillService.selectSeckillBySid(sid));
    }

    /**
     * 新增秒杀
     */
    @RequiresPermissions("system:seckill:add")
    @Log(title = "秒杀", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    public AjaxResult add(@RequestBody Seckill seckill)
    {
        return toAjax(seckillService.insertSeckill(seckill));
    }

    /**
     * 修改秒杀
     */
    @RequiresPermissions("system:seckill:edit")
    @Log(title = "秒杀", businessType = BusinessType.UPDATE)
    @PutMapping("/edit")
    public AjaxResult edit(@RequestBody Seckill seckill)
    {
        return toAjax(seckillService.updateSeckill(seckill));
    }

    /**
     * 删除秒杀
     */
    @RequiresPermissions("system:seckill:remove")
    @Log(title = "秒杀", businessType = BusinessType.DELETE)
	@DeleteMapping("remove/{sids}")
    public AjaxResult remove(@PathVariable Long[] sids)
    {
        return toAjax(seckillService.deleteSeckillBySids(sids));
    }



    /**
     * 秒杀
     * @param
     * @param
     * @param
     * @return
     */
    @RequestMapping("/seckill/{eid}/{uid}/{pid}")
    public ResultObject<Map> seckill(@PathVariable Long eid,@PathVariable Long uid,@PathVariable Long pid) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        lock.lock();
        try {
            //获取活动信息
            Event event = iEventService.selectEventByEid(eid);
            Date startTime = event.getStartTime();
            Date endTime = event.getEndTime();
            Date now = new Date();
            if(now.before(startTime)){
                return new ResultObject<>(false,"0","活动未开始",null);
            }

            if(now.after(endTime)){
                return new ResultObject<>(false,"0","活动已经结束",null);
            }
            Preferential preferential = (Preferential) redisTemplate.opsForHash().get("YHHD" + eid.toString(), pid.toString());

            //判断这个人是否抢过优惠卷 （每个人只能抢3三张）
            Long o2 = (Long) redisTemplate.opsForValue().get("QcountSum"+pid.toString());
            Long receiveCount=0l;
            if(o2!=null){
                receiveCount=o2;
            }
            Long publishCount = Long.parseLong(preferential.getPnum().toString());

            if(publishCount<=receiveCount){
                System.out.println("优惠卷已经领完了,receiveCount="+receiveCount);
                return new ResultObject<>(false,"0","优惠券已经领完",null);
            }
            //个人抢到的优惠卷
            Integer userCount = (Integer) redisTemplate.opsForHash().get("CouponCount:" + pid.toString(), uid.toString());

            if(userCount==null){
                userCount=0;
            }
            //判断
            if(userCount>=3){
                return new ResultObject<>(false,"0","您已经抢超过最大限制",null);
            }


            try{
                //redisTemplate.multi();

                redisTemplate.opsForHash().put("CouponCount:" + pid.toString(),uid.toString(),userCount+1);
                redisTemplate.opsForValue().increment("QcountSum"+pid,1L);
                //redisTemplate.exec();
                Map map= new HashMap();
                map.put("pid",pid);
                map.put("uid",uid);
                map.put("eid",eid);
                rabbitTemplate.convertAndSend("","Queue_Seckill",map,(message)->{
                    message.getMessageProperties().setMessageId(String.valueOf(idWorker.nextId()));
                    return message;
                });
                stopWatch.stop();
                long totalTimeMillis = stopWatch.getTotalTimeMillis();
                System.out.println("本次秒杀接口花费时间=" + totalTimeMillis + "(ms)");
                return new ResultObject<>(true,"1","恭喜您抢成功！",null);
            }catch (Exception e){

                e.printStackTrace();
                return new ResultObject<>(false, "0", "出现异常！", null);
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }


        return null;
    }

    @SentinelResource(value = "secKill",blockHandler = "secKillBlockHandler",fallback = "secKillFallbackHandler")
    //限流后的执行方法 FlowException
    public void blockHandler(String msg, BlockException ex) {
        System.out.println("blockHandler ---method1 "+ msg);
        ex.printStackTrace();
    }
    //出现异常 熔断，降级的业务逻辑
    public void fallbackHandler(String msg){
        System.out.println("fallbackHandler ---method1 "+ msg);
    }
//
//
//​
//    //随着线上的机子量变化需要修改限流数，目前是10秒3个请求
//    private static volatile int permit = 3;
//​
//    private Map<Long, Integer> rate = new ConcurrentHashMap<>(500);
//​
//    public boolean limit() {
//        long secondTime = System.currentTimeMillis() / 10000;
//        synchronized (SeckillController.class) {
//            Integer count = rate.get(secondTime);
//            if (count == null) {
//                rate.put(secondTime, 1);
//                rate.remove(secondTime - 3);
//                System.out.println("开始-------count ：" + count + 1);
//                return true;
//            }
//            if (count + 1 > permit) {
//                System.out.println("限流了 -------" + count + 1);
//                return false;
//            }
//            rate.put(secondTime, count + 1);
//            System.out.println("通过了-------" + count + 1);
//            return true;
//        }
//    }






}
